/*
 * lcd.c
 *
 *  Created on: Mar 21, 2011
 *      Author: Vishal Verma
 */

#include <at89c51ed2.h>  							//also includes 8052.h and 8051.h
#include <mcs51reg.h>
#include <string.h>
#include <stdio.h>
#include "lcd.h"
#include "i2c.h"
#include "delay.h"

__xdata __at LCD_ADDR volatile unsigned int lcdPtr;

int f_skipBusyChk = TRUE;						//dont check busy flag if init is not complete
unsigned char cursorPos = LCDHOME | LCD0OFFSET;

/*
* NAME :            lcdinit
*
* DESCRIPTION :     initialize lcd
*
* INPUTS :
*       PARAMETERS:	-
*		GLOBALS:	-
*
* OUTPUTS :
*		PARAMETERS: -
*       GLOBALS :	-
*       RETURN :	-
*
* PROCESS :
*                   [1]  
*
* NOTES :           -
*/

void lcdinit(void) {								// Init routine as per HD44780 data sheet

	LCD_RS = RS_CMD;
	LCD_RW = RW_WRITE;
	delay_millisec(16);                            	// Wait more than 15ms
    lcdCmd(0x38);                             		// Initialize for 8 bit mode , 4 lines
    delay_millisec(5);                              // Wait more than 4.1ms
    lcdCmd(0x38);
    delay_millisec(1);                             	// Wait more than 0.1ms
    lcdCmd(0x38);
    delay_millisec(1);                             	// Wait more than 0.1ms
    lcdCmd(0x0D);                             		// Display On; Cursor On; Blink On
    lcdCmd(0x01);                             		// Clear the display
    delay_millisec(5);                            	// Wait more than 1.64ms
    f_skipBusyChk = FALSE;
}

/*
* NAME :            lcdCmd
*
* DESCRIPTION :     write to lcd command register
*
* INPUTS :
*       PARAMETERS:	wrCmd
*		GLOBALS:	-
*
* OUTPUTS :
*		PARAMETERS: -
*       GLOBALS :	-
*       RETURN :	-
*
* PROCESS :
*                   [1]  check busy flag and write command
*
* NOTES :           
*/

void lcdCmd(char wrCmd)					 			// Write a command to the LCD.
{
	lcdbusywait();                                  	// Is the LCD ready to take the command?
    LCD_RS = RS_CMD;                                // Register Select Low for writing command
    LCD_RW = RW_WRITE;                              // R!W low for write
    LCD_PORT = wrCmd;                          		// Command byte to register
    //LCD_RS   = RS_CMD;
    //LCD_RW   = RW_READ;
}

/*
* NAME :            lcdputch
*
* DESCRIPTION :     write to lcd data register
*
* INPUTS :
*       PARAMETERS:	-
*		GLOBALS:	-
*
* OUTPUTS :
*		PARAMETERS: -
*       GLOBALS :	-
*       RETURN :	-
*
* PROCESS :
*                   [1]  check busy flag and write data
*
* NOTES :           
*/

void lcdputch(char wrData)	{						// Write a character to the LCD.
	
	lcdbusywait();                                  // Is the LCD ready to take the command?
    LCD_RS = RS_DATA;                               // Register Select High for writing data
    LCD_RW = RW_WRITE;                              // R!W low for write

    LCD_PORT = wrData;                          	// Data byte to data port

    if (cursorPos == (LCDHOME | LCD0END)) {
		lcdCmd(LCDHOME | LCD1OFFSET);
		cursorPos = LCDHOME | LCD1OFFSET;
	}
    else if (cursorPos == (LCDHOME | LCD1END)) {
		lcdCmd(LCDHOME | LCD2OFFSET);
		cursorPos = LCDHOME | LCD2OFFSET;
	}
    else if (cursorPos == (LCDHOME | LCD2END)) {
		lcdCmd(LCDHOME | LCD3OFFSET);
		cursorPos = LCDHOME | LCD3OFFSET;
	}
    else if (cursorPos == (LCDHOME | LCD3END)) {
		lcdCmd(LCDHOME | LCD0OFFSET);
		cursorPos = LCDHOME | LCD0OFFSET;
	}
    else {
    	cursorPos++;
    }

    //LCD_RS   = RS_CMD;
    //LCD_RW   = RW_READ;
}

/*
* NAME :            lcdbusywait
*
* DESCRIPTION :     check for busy flag, block if busy
*
* INPUTS :
*       PARAMETERS:	-
*		GLOBALS:	-
*
* OUTPUTS :
*		PARAMETERS: - 
*       GLOBALS :	-
*       RETURN :	-
*
* PROCESS :
*                   [1] read register and if busy, wait  
*
* NOTES :           -
*/

void lcdbusywait(void) {

	volatile unsigned char rdCmd = 0;

	if (FALSE == f_skipBusyChk) {
		P0 = 0xFF ;                                  // Set port as input
		LCD_RS   = RS_CMD;
		LCD_RW   = RW_READ;

		do {
			rdCmd = LCD_PORT;
		}while (rdCmd & 0x80);
	}
}

/*
* NAME :            lcdgotoaddr
*
* DESCRIPTION :     go to DDRAM address
*
* INPUTS :
*       PARAMETERS:	addr
*		GLOBALS:	-
*
* OUTPUTS :
*		PARAMETERS: -
*       GLOBALS :	-
*       RETURN :	-
*
* PROCESS :
*                   [1]  
*
* NOTES :           
*/

void lcdgotoaddr (unsigned char addr) {

	if(addr < 0x80) {
		lcdbusywait();
		lcdCmd(LCDHOME | addr);
		cursorPos = LCDHOME | addr;
	}
}

/*
* NAME :            lcdgotoxy
*
* DESCRIPTION :     go to x,y coordinate
*
* INPUTS :
*       PARAMETERS:	row, col
*		GLOBALS:	-
*
* OUTPUTS :
*		PARAMETERS: -
*       GLOBALS :	-
*       RETURN :	-
*
* PROCESS :
*                   [1]  convert x,y to DDRAM address and go to address
*
* NOTES :           
*/

void lcdgotoxy (unsigned char row, unsigned char col) {
	if((row < LCDHEIGHT) && (col < LCDWIDTH)) {
		switch (row) {
			case 0: lcdgotoaddr(LCD0OFFSET + col); break;
			case 1: lcdgotoaddr(LCD1OFFSET + col); break;
			case 2: lcdgotoaddr(LCD2OFFSET + col); break;
			case 3: lcdgotoaddr(LCD3OFFSET + col); break;
			default: lcdgotoaddr(LCDHOME);
		} //switch
	} //sanity
}

/*
* NAME :            lcdputstr
*
* DESCRIPTION :     print string to lcd
*
* INPUTS :
*       PARAMETERS:	string
*		GLOBALS:	-
*
* OUTPUTS :
*		PARAMETERS: -
*       GLOBALS :	-
*       RETURN :	-
*
* PROCESS :
*                   [1] put characters till \0 encountered  
*
* NOTES :           
*/

void lcdputstr (char *string) {					 	// Write the 2 line message to LCD

	int i;

	for (i=0; i<=strlen(string)-1; ++i)	{
		lcdputch(string[i]);
	}
}

/*
* NAME :            clrLcd
*
* DESCRIPTION :     clear the lcd screen
*
* INPUTS :
*       PARAMETERS:	-
*		GLOBALS:	-
*
* OUTPUTS :
*		PARAMETERS: -
*       GLOBALS :	-
*       RETURN :	-
*
* PROCESS :
*                   [1] send clear and home commands to lcd register  
*
* NOTES :           
*/

void clrLcd () {

	lcdCmd(LCDCLEAR); 									//-- clear LCD display
	lcdCmd(LCDHOME); 									//-- cursor go to 0x00
	cursorPos = LCDHOME | LCD0OFFSET;
	delay_millisec(5);
}

/*
* NAME :            lcdHome
*
* DESCRIPTION :     go to home position
*
* INPUTS :
*       PARAMETERS:	
*		GLOBALS:	
*
* OUTPUTS :
*		PARAMETERS: 
*       GLOBALS :	
*       RETURN :	
*
* PROCESS :
*                   [1]  
*
* NOTES :           
*/

void lcdHome () {

	lcdCmd(LCDHOME); 									//-- cursor go to 0x00
	cursorPos = LCDHOME | LCD0OFFSET;
}

/*
* NAME :            lcdPrintToLine
*
* DESCRIPTION :     Print string to specific line. lruncate if >16
*
* INPUTS :
*       PARAMETERS:	
*		GLOBALS:	
*
* OUTPUTS :
*		PARAMETERS: 
*       GLOBALS :	
*       RETURN :	
*
* PROCESS :
*                   [1]  
*
* NOTES :           
*/

void lcdPrintToLine(unsigned int line, char *string) {

	int size = 0;

	if (line <= 3) {
		lcdgotoxy(line,0);
		size = strlen(string)-1;
		if (size > LCDWIDTH) {
			string[LCDWIDTH] = 0;
		}
		lcdputstr(string);
	}
}

/*
* NAME :            lcdPrintf1Int
*
* DESCRIPTION :     Emulating printf function for lcd for 1 line
*
* INPUTS :
*       PARAMETERS:	
*		GLOBALS:	
*
* OUTPUTS :
*		PARAMETERS: 
*       GLOBALS :	
*       RETURN :	
*
* PROCESS :
*                   [1]  
*
* NOTES :           
*/

void lcdPrintf1Int(unsigned int line, char *string, int int1) {

	char str[2*LCDWIDTH] = {0};

	sprintf(str, string, int1);
	if ((strlen(str)-1) > LCDWIDTH) {
		str[LCDWIDTH] = 0;
	}
	lcdPrintToLine(line, str);
}

/*
* NAME :            lcdPrintf2Int
*
* DESCRIPTION :     Emulating printf function for lcd for 2 int
*
* INPUTS :
*       PARAMETERS:	
*		GLOBALS:	
*
* OUTPUTS :
*		PARAMETERS: 
*       GLOBALS :	
*       RETURN :	
*
* PROCESS :
*                   [1]  
*
* NOTES :           
*/

void lcdPrintf2Int(unsigned int line, char *string, int int1, int int2) {

	char str[2*LCDWIDTH] = {0};

	sprintf(str, string, int1, int2);
	if ((strlen(str)-1) > LCDWIDTH) {
		str[LCDWIDTH] = 0;
	}
	lcdPrintToLine(line, str);
}

/*
* NAME :            lcdPrintf3Int
*
* DESCRIPTION :     Emulating printf function for lcd for 3 ints
*
* INPUTS :
*       PARAMETERS:	
*		GLOBALS:	
*
* OUTPUTS :
*		PARAMETERS: 
*       GLOBALS :	
*       RETURN :	
*
* PROCESS :
*                   [1]  
*
* NOTES :           
*/

void lcdPrintf3Int(unsigned int line, char *string, int int1, int int2, int int3) {

	char str[2*LCDWIDTH] = {0};

	sprintf(str, string, int1, int2, int3);
	if ((strlen(str)-1) > LCDWIDTH) {
		str[LCDWIDTH] = 0;
	}
	lcdPrintToLine(line, str);
}

/*
* NAME :            clrLine
*
* DESCRIPTION :     Clear specific line
*
* INPUTS :
*       PARAMETERS:	
*		GLOBALS:	
*
* OUTPUTS :
*		PARAMETERS: 
*       GLOBALS :	
*       RETURN :	
*
* PROCESS :
*                   [1]  
*
* NOTES :           
*/

void clrLine(unsigned int line) {

	int size = 0;

	if (line <= 3) {
		lcdPrintToLine(line, LCDLINECLR);
		lcdgotoxy(line,0);
	}
}

/*
* NAME :            lcdcreatechar
*
* DESCRIPTION :     Create custom character for LCD
*
* INPUTS :
*       PARAMETERS:	
*		GLOBALS:	
*
* OUTPUTS :
*		PARAMETERS: 
*       GLOBALS :	
*       RETURN :	
*
* PROCESS :
*                   [1]  save DDRAM state
*					[2]  write custom char to CGRAM addresses
*					[3]  restore DDRAM state
*
* NOTES :           
*/

void lcdcreatechar(unsigned char ccode, unsigned char row_vals[]) {

	unsigned char i = 0;
	unsigned char state = 0;

	LCD_RS   = RS_CMD;
	LCD_RW   = RW_READ;
	state = LCD_PORT;

	for (i=0; i<CUSTCHARROWS; i++) {
		lcdCmd( CGRAMOFFSET | (ccode<<3) | i );
		lcdputch(row_vals[i]);
	}

	lcdCmd(state);
}



